home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / perl5 / Glib / GenPod.pm < prev    next >
Encoding:
Perl POD Document  |  2006-01-28  |  30.5 KB  |  1,277 lines

  1. #
  2. #
  3. #
  4. # TODO:
  5. #    should we look at signals etc. for enums/flags?
  6. #    we're getting warnings about unregistered types with new enums/flags 
  7. #    stuff, quell them.
  8. #
  9.  
  10. package Glib::GenPod;
  11.  
  12. our $VERSION = '0.02';
  13.  
  14. use strict;
  15. use warnings;
  16. use Carp;
  17. use File::Spec;
  18. use Data::Dumper;
  19. use POSIX qw(strftime);
  20.  
  21. use Glib;
  22.  
  23. use base 'Exporter';
  24.  
  25. our @EXPORT = qw(
  26.     add_types
  27.     xsdoc2pod
  28.     podify_properties
  29.     podify_values
  30.     podify_signals
  31.     podify_ancestors
  32.     podify_interfaces
  33.     podify_methods
  34.     podify_enums_and_flags
  35. );
  36.  
  37. our $COPYRIGHT = undef;
  38. our $AUTHORS = 'Gtk2-Perl Team';
  39. our $MAIN_MOD = undef;
  40. our $YEAR = strftime "%Y", gmtime;
  41.  
  42. our ($xspods, $data);
  43.     
  44. =head1 NAME
  45.  
  46. Glib::GenPod - POD generation utilities for Glib-based modules
  47.  
  48. =head1 SYNOPSIS
  49.  
  50.  use Glib::GenPod;
  51.  
  52.  # use the defaults:
  53.  xsdoc2pod ($xsdocparse_output_file, $destination_dir);
  54.  
  55.  # or take matters into your own hands
  56.  require $xsdocparse_output_file;
  57.  foreach my $package (sort keys %$data) {
  58.      print "=head1 NAME\n\n$package\n\n";
  59.      print "=head1 METHODS\n\n" . podify_methods ($package) . "\n\n";
  60.  }
  61.  
  62. =head1 DESCRIPTION 
  63.  
  64. This module includes several utilities for creating pod for xs-based Perl
  65. modules which build on the Glib module's foundations.  The most important bits
  66. are the logic to convert the data structures created by xsdocparse.pl to
  67. describe xsubs and pods into method docs, with call signatures and argument
  68. descriptions, and converting C type names into Perl type names.  The rest of
  69. the module is mostly boiler-plate code to format and pretty-print information
  70. that may be queried from the Glib type system.
  71.  
  72. To make life easy for module maintainers, we also include a do-it-all function,
  73. xsdoc2pod(), which does pretty much everything for you.  All of the pieces it
  74. uses are publically usable, so you can do whatever you like if you don't like
  75. the default output.
  76.  
  77. =head1 DOCUMENTING THE XS FILES
  78.  
  79. All of the information used as input to the methods included here comes from
  80. the XS files of your project, and is extracted by Glib::ParseXSDoc's
  81. C<xsdocparse>.  This function creates an file containing Perl code that may be
  82. eval'd or require'd to recreate the parsed data structures, which are a list of
  83. pods from the verbatim C portion of the XS file (the xs api docs), and a hash
  84. of the remaining data, keyed by package name, and including the pods and xsubs
  85. read from the rest of each XS file following the first MODULE line.
  86.  
  87. Several custom POD directives are recognized in the XSubs section.  Note that
  88. each one is sought as a paragraph starter, and must follow a C<=cut> directive.
  89.  
  90. =over
  91.  
  92. =item =for object Package::Name
  93.  
  94. All xsubs and pod from here until the next object directive or MODULE line
  95. will be placed under the key 'I<Package::Name>' in xsdocparse's data
  96. structure.  Everything from this line to the next C<=cut> is included as a
  97. description POD.
  98.  
  99. =item =for enum Package::Name
  100.  
  101. =item =for flags Package::Name
  102.  
  103. This causes xsdoc2pod to call C<podify_values> on I<Package::Name> when
  104. writing the pod for the current package (as set by an object directive or
  105. MODULE line).  Any text in this paragraph, to the next C<=cut>, is included
  106. in that section.
  107.  
  108. =item =for see_also L<some_thing_to_see>
  109.  
  110. Used to add extra see alsos onto the end of the parents, if any, for a given
  111. object.  Anything following the space behind see_also up to the end of the
  112. line will be placed onto the list of "see also"s.  There may be any number of
  113. these in each package.
  114.  
  115. =item =for apidoc
  116.  
  117. =item =for apidoc Full::Symbol::name
  118.  
  119. Paragraphs of this type document xsubs, and are associated with the xsubs
  120. by xsdocparse.pl.  If the full symbol name is not included, the paragraph
  121. must be attached to the xsub declaration (no blank lines between C<=cut> and
  122. the xsub).
  123.  
  124. Within the apidoc PODs, we recognize a few special directives (the "for\s+"
  125. is optional on these):
  126.  
  127. =over
  128.  
  129. =item =for signature ...
  130.  
  131. Override the generated call signature with the ... text.  If you include
  132. multiple signature directives, they will all be used.  This is handy when
  133. you want to change the return type or list different ways to invoke an
  134. overloaded method, like this:
  135.  
  136.  =for apidoc
  137.  
  138.  =signature bool Class->foo
  139.  
  140.  =signature ($thing, @other) = $object->foo ($it, $something)
  141.  
  142.  Text in here is included in the generated documentation.
  143.  You can actually include signature and arg directives
  144.  at any point in this pod -- they are stripped after.
  145.  In fact, any pod is valid in here, until the =cut.
  146.  
  147.  =cut
  148.  void foo (...)
  149.      PPCODE:
  150.         /* crazy code follows */
  151.  
  152. =item =for arg name (type) description
  153.  
  154. =item =for arg name description
  155.  
  156. The arg directive adds or overrides an argument description.  The
  157. description text is optional, as is the type specification (the part
  158. in parentheses).  The arg name does I<not> need to include a sigil,
  159. as dollar signs will be added.  FIXME what about @ for lists?
  160.  
  161. =back
  162.  
  163. Also, we honor a couple of "modifiers" on the =for apidoc line, following the
  164. symbol name, if present:
  165.  
  166. =over
  167.  
  168. =item - __hide__
  169.  
  170. Do not document this xsub.  This is handy in certain situations, e.g., for
  171. private functions.  DESTROY always has this turned on, for example.
  172.  
  173. =item - __gerror__
  174.  
  175. This function or method can generate a Glib::Error exception.
  176.  
  177. =item - __function__
  178.  
  179. Generate a function-style signature for this xsub.  The default is to
  180. generate method-style signatures.
  181.  
  182. =back
  183.  
  184. (These are actually handled by Glib::ParseXSDoc, but we list them here
  185. because, well, they're an important part of how you document the XS files.)
  186.  
  187. =back
  188.  
  189. =head1 FUNCTIONS
  190.  
  191. =over
  192.  
  193. =cut
  194.  
  195. =item xsdoc2pod ($datafile, $outdir='blib/lib', index=undef)
  196.  
  197. Given a I<$datafile> containing the output of xsdocparse.pl, create in 
  198. I<$outdir> a pod file for each package, containing everything we can think
  199. of for that module.  Output is controlled by the C<=for object> directives
  200. and such in the source code.
  201.  
  202. If you don't want each package to create a separate pod file, then use
  203. this function's code as a starting point for your own pretty-printer.
  204.  
  205. =cut
  206. sub xsdoc2pod
  207. {
  208.     my $datafile = shift();
  209.     my $outdir   = shift() || 'blib/lib';
  210.     my $index    = shift;
  211.  
  212.     mkdir $outdir unless (-d $outdir);
  213.  
  214.     die "usage: $0 datafile [outdir]\n"
  215.         unless defined $datafile;
  216.  
  217.     require $datafile;
  218.  
  219.     my @files = ();
  220.  
  221.     my $pkgdata;
  222.     my $ret;
  223.  
  224.     foreach my $package (sort { ($a->isa('Glib::Object') ? -1 : 1) } 
  225.                 keys %$data)
  226.     {
  227.         $pkgdata = $data->{$package};
  228.  
  229.         my $pod = File::Spec->catfile ($outdir, split /::/, $package)
  230.                 . '.pod';
  231.         my (undef, @dirs, undef) = File::Spec->splitpath ($pod);
  232.         mkdir_p (File::Spec->catdir (@dirs));
  233.  
  234.         open POD, ">$pod" or die "can't open $pod for writing: $!\n";
  235.         select POD;
  236.         print STDERR "podifying $pod\n";
  237.  
  238.         $package = $pkgdata->{object} if (exists $pkgdata->{object});
  239.  
  240.         preprocess_pod ($_) foreach (@{$pkgdata->{pods}});
  241.  
  242.         push @files, {
  243.             name => $package,
  244.             file => $pod,
  245.             blurb => $pkgdata->{blurb},
  246.         };
  247.  
  248.         print "=head1 NAME\n\n$package";
  249.         print ' - '.$pkgdata->{blurb} if (exists ($pkgdata->{blurb}));
  250.         print "\n\n";
  251.  
  252.         #                   pods            , position 
  253.         $ret = podify_pods ($pkgdata->{pods}, 'SYNOPSIS');
  254.         print "$ret\n\n" if ($ret);
  255.         
  256.         $ret = podify_pods ($pkgdata->{pods}, 'DESCRIPTION');
  257.         print "$ret\n\n" if ($ret);
  258.         
  259.         my $parents;
  260.         ($ret, $parents) = podify_ancestors ($package);
  261.         print "=head1 HIERARCHY\n\n$ret" if ($ret);
  262.         
  263.         $ret = podify_pods ($pkgdata->{pods}, 'post_hierarchy');
  264.         print "$ret\n\n" if ($ret);
  265.         
  266.         $ret = podify_interfaces ($package);
  267.         print "=head1 INTERFACES\n\n$ret" if ($ret);
  268.         
  269.         $ret = podify_pods ($pkgdata->{pods}, 'post_interfaces');
  270.         print "$ret\n\n" if ($ret);
  271.  
  272.         $ret = podify_pods ($pkgdata->{pods});
  273.         print "$ret\n\n" if ($ret);
  274.  
  275.         $ret = podify_methods ($package, $pkgdata->{xsubs});
  276.         print "\n=head1 METHODS\n\n$ret" if ($ret);
  277.         
  278.         $ret = podify_pods ($pkgdata->{pods}, 'post_methods');
  279.         print "$ret\n\n" if ($ret);
  280.  
  281.         $ret = podify_properties ($package);    
  282.         print "\n=head1 PROPERTIES\n\n$ret" if ($ret);
  283.  
  284.         $ret = podify_pods ($pkgdata->{pods}, 'post_properties');
  285.         print "$ret\n\n" if ($ret);
  286.  
  287.         $ret = podify_signals ($package);    
  288.         print "\n=head1 SIGNALS\n\n$ret" if ($ret);
  289.  
  290.         $ret = podify_pods ($pkgdata->{pods}, 'post_signals');
  291.         print "$ret\n\n" if ($ret);
  292.  
  293.         $ret = podify_enums_and_flags ($pkgdata, $package);    
  294.         print "\n=head1 ENUMS AND FLAGS\n\n$ret" if ($ret);
  295.  
  296.         $ret = podify_pods ($pkgdata->{pods}, 'post_enums');
  297.         print "$ret\n\n" if ($ret);
  298.  
  299.         $ret = podify_pods ($pkgdata->{pods}, 'SEE_ALSO');
  300.         if ($ret)
  301.         {
  302.             print "$ret\n\n";
  303.         }
  304.         else
  305.         {
  306.             # don't link to yourself
  307.             pop @$parents;
  308.             # link to the toplevel, if we can.
  309.             unshift @$parents, $MAIN_MOD if $MAIN_MOD;
  310.  
  311.             $ret = podify_see_alsos (@$parents,
  312.                                      $pkgdata->{see_alsos}
  313.                          ? @{ $pkgdata->{see_alsos} }
  314.                                      : ());
  315.             print "\n=head1 SEE ALSO\n\n$ret" if ($ret);
  316.         }
  317.  
  318.         $ret = podify_pods ($pkgdata->{pods}, 'COPYRIGHT');
  319.         if ($ret)
  320.         {
  321.             # copyright over-ridden
  322.             print "$ret\n\n" 
  323.         }
  324.         else
  325.         {
  326.             # use normal copyright system
  327.             $ret = get_copyright ();
  328.             print "\n=head1 COPYRIGHT\n\n$ret" if ($ret);
  329.         }
  330.  
  331.         print "\n=cut\n\n";
  332.  
  333.         close POD;
  334.     }
  335.  
  336.     if ($index) {
  337.         open INDEX, ">$index"
  338.             or die "can't open $index for writing: $!\b";
  339.         select INDEX;
  340.  
  341.         foreach (sort {$a->{name} cmp $b->{name}} @files) {
  342.             print join("\t", $_->{file},
  343.                    $_->{name},
  344.                    $_->{blurb} ? $_->{blurb} : () ) . "\n";
  345.         }
  346.         
  347.         close INDEX;
  348.     }
  349. }
  350.  
  351. # more sensible names for the basic types
  352. our %basic_types = (
  353.     # the perl wrappers for the GLib fundamentals
  354.     'Glib::Scalar'  => 'scalar',
  355.     'Glib::String'  => 'string',
  356.     'Glib::Int'     => 'integer',
  357.     'Glib::Uint'    => 'unsigned',
  358.     'Glib::Double'  => 'double',
  359.     'Glib::Boolean' => 'boolean',
  360.  
  361.     # sometimes we can get names that are already mapped...
  362.     # e.g., from =for arg lines.  pass them unbothered.
  363.     scalar     => 'scalar',
  364.     subroutine => 'subroutine',
  365.     integer    => 'integer',
  366.     string     => 'string',
  367.  
  368.     # other C names which may sneak through
  369.     bool     => 'boolean', # C++ keyword, but provided by the perl api
  370.     boolean  => 'boolean',
  371.     int      => 'integer',
  372.     char     => 'integer',
  373.     uint     => 'unsigned',
  374.     float    => 'double',
  375.     double   => 'double',
  376.     char     => 'string',
  377.     unsigned => 'unsigned',
  378.  
  379.     gboolean => 'boolean',
  380.     gint     => 'integer',
  381.     gint8    => 'integer',
  382.     gint16   => 'integer',
  383.     gint32   => 'integer',
  384.     guint8   => 'unsigned',
  385.     guint16  => 'unsigned',
  386.     guint32  => 'unsigned',
  387.     gulong   => 'unsigned',
  388.     gshort   => 'integer',
  389.     guint    => 'integer',
  390.     gushort  => 'unsigned',
  391.     gfloat   => 'double',
  392.     gdouble  => 'double',
  393.     gchar    => 'string',
  394.  
  395.     SV       => 'scalar',
  396.     UV       => 'unsigned',
  397.     IV       => 'integer',
  398.     CV       => 'subroutine',
  399.  
  400.     gchar_length => 'string',
  401.  
  402.     FILE => 'file handle',
  403.     time_t => 'unix timestamp',
  404.  
  405.     GPerlFilename    => 'localized file name',
  406.     GPerlFilename_const    => 'localized file name',
  407. );
  408.  
  409. unless (Glib->CHECK_VERSION (2, 4, 0)) {
  410.     $basic_types{'Glib::Strv'} = 'ref to array of strings';
  411. }
  412.  
  413. =item add_types (@filenames)
  414.  
  415. Parse the given I<@filenames> for entries to add to the C<%basic_types> used
  416. for C type name to Perl package name mappings of types that are not registered
  417. with the Glib type system.  The file format is dead simple: blank lines are
  418. ignored; /#.*$/ is stripped from each line as comments; the first token on
  419. each line is considered to be a C type name, and the remaining tokens are the
  420. description of that type.  For example, a valid file may look like this:
  421.  
  422.   # a couple of special types
  423.   FooBar      Foo::Bar
  424.   Frob        localized frobnicator
  425.  
  426. C type decorations such as "const" and "*" are implied (do not include them),
  427. and the _ornull variant is handled for you.
  428.  
  429. =cut
  430. sub add_types {
  431.     my @files = @_;
  432.     foreach my $f (@files) {
  433.         open IN, $f or die "can't open types file $f: $!\n";
  434.         my $n = 0;
  435.         while (<IN>) {
  436.             chomp;
  437.             s/#.*//;
  438.             next if m/^\s*$/;
  439.             my ($c_name, @bits) = split;
  440.             if (@bits) {
  441.                 $basic_types{$c_name} = join ' ', @bits;
  442.                 $n++;
  443.             } else {
  444.                 warn "$f:$.: no description for $c_name\n"
  445.             }
  446.         }
  447.         print "loaded $n extra types from $f\n";
  448.         close IN;
  449.     }
  450. }
  451.  
  452.  
  453. =item $string = podify_properties ($packagename)
  454.  
  455. Pretty-print the object properties owned by the Glib::Object derivative
  456. I<$packagename> and return the text as a string.  Returns undef if there
  457. are no properties or I<$package> is not a Glib::Object.
  458.  
  459. =cut
  460. sub podify_properties {
  461.     my $package = shift;
  462.     my @properties;
  463.     eval { @properties = Glib::Object::list_properties($package); 1; };
  464.     return undef unless (@properties or not $@);
  465.  
  466.     # we have a non-zero number of properties, but there may still be
  467.     # none for this particular class.  keep a count of how many
  468.     # match this class, so we can return undef if there were none.
  469.     my $nmatch = 0;
  470.     my $str = "=over\n\n";
  471.     foreach my $p (sort { $a->{name} cmp $b->{name} } @properties) {
  472.         next unless $p->{owner_type} eq $package;
  473.         ++$nmatch;
  474.         my $stat = join " / ",  @{ $p->{flags} };
  475.         my $type = exists $basic_types{$p->{type}}
  476.               ? $basic_types{$p->{type}}
  477.               : $p->{type};
  478.         $str .= "=item '$p->{name}' ($type : $stat)\n\n";
  479.         $str .= "$p->{descr}\n\n" if (exists ($p->{descr}));
  480.     }
  481.     $str .= "=back\n\n";
  482.  
  483.     return $nmatch ? $str : undef;
  484. }
  485.  
  486. =item $string = podify_values ($packagename)
  487.  
  488. List and pretty-print the values of the GEnum or GFlags type I<$packagename>,
  489. and return the text as a string.  Returns undef if I<$packagename> isn't an
  490. enum or flags type.
  491.  
  492. =cut
  493. sub podify_values {
  494.     my $package = shift;
  495.     my @values;
  496.     eval { @values = Glib::Type->list_values ($package); 1; };
  497.     return undef unless (@values or not $@);
  498.  
  499.     return "=over\n\n"
  500.          . join ("\n\n", map { "=item * '$_->{nick}' / '$_->{name}'" } @values)
  501.          . "\n\n=back\n\n";
  502. }
  503.  
  504. =item $string = podify_signals ($packagename)
  505.  
  506. Query, list, and pretty-print the signals associated with I<$packagename>.
  507. Returns the text as a string, or undef if there are no signals or
  508. I<$packagename> is not a Glib::Object derivative.
  509.  
  510. =cut
  511. sub podify_signals {
  512.     my $str = undef;
  513.     eval {
  514.     my @sigs = Glib::Type->list_signals (shift);
  515.     return undef unless @sigs;
  516.     $str = "=over\n\n";
  517.     foreach (@sigs) {
  518.         $str .= '=item ';
  519.         $str .= convert_type ($_->{return_type}).' = '
  520.             if exists $_->{return_type};
  521.         $str .= "B<$_->{signal_name}> (";
  522.         $str .= join ', ', map { convert_type ($_) }
  523.                 $_->{itype}, @{$_->{param_types}};
  524.         $str .= ")\n\n";
  525.     }
  526.     $str .= "=back\n\n";
  527.     };
  528.     return $str
  529. }
  530.  
  531. sub podify_enums_and_flags
  532. {
  533.     my $pkgdata = shift;
  534.     my $package = shift;
  535.     
  536.     my %types = ();
  537.     
  538.     my $name;
  539.     my $pod;
  540.     my %info = ();
  541.     foreach (@{$pkgdata->{enums}})
  542.     {
  543.         $name = convert_type ($_->{name});
  544.             
  545.         $pod = $_->{pod};
  546.         shift @{ $pod->{lines} };
  547.         pop @{ $pod->{lines} } if $pod->{lines}[-1] =~ /^=cut/;
  548.  
  549.         $info{$name} = {
  550.             type => $_->{type},
  551.             pod  => $pod->{lines},
  552.         };
  553.         $types{$name}++;
  554.     }
  555.  
  556.     foreach my $xsub (@{$pkgdata->{xsubs}})
  557.     {
  558.         if ($xsub->{return_type})
  559.         {
  560.             foreach my $ret (@{$xsub->{return_type}})
  561.             {
  562.                 $name = convert_type ($ret);
  563.                 $types{$name}++;
  564.             }
  565.         }
  566.         if ($xsub->{args})
  567.         {
  568.             foreach my $arg (@{$xsub->{args}})
  569.             {
  570.                 if ($arg->{type})
  571.                 {
  572.                     $name = convert_type ($arg->{type});
  573.                     $types{$name}++;
  574.                 }
  575.             }
  576.         }
  577.     }
  578.  
  579.     if ($package)
  580.     {
  581.         my @props;
  582.         eval { @props = Glib::Object::list_properties($package); 1; };
  583.         foreach my $prop (@props)
  584.         {
  585.             next unless ($prop->{type});
  586.             next unless $prop->{owner_type} eq $package;
  587.             $name = convert_type ($prop->{type});
  588.             $types{$name}++;
  589.         }
  590.         
  591.         my @sigs;
  592.         eval { @sigs = Glib::Type->list_signals ($package); 1; };
  593.         foreach my $sig (@sigs)
  594.         {
  595.             if ($sig->{return_type})
  596.             {
  597.                 $name = convert_type ($sig->{return_type});
  598.                 $types{$name}++;
  599.             }
  600.             foreach (@{$sig->{param_types}})
  601.             {
  602.                 next unless ($_);
  603.                 $name = convert_type ($_);
  604.                 $types{$name}++;
  605.             }
  606.         }
  607.     }
  608.  
  609.     my $ret = '';
  610.     foreach (sort keys %types)
  611.     {
  612.         s/\s.*//;
  613.  
  614.         my $values_pod = podify_values ($_);
  615.  
  616.         if ($values_pod || exists $info{$_})
  617.         {
  618.             my $type = UNIVERSAL::isa ($_, 'Glib::Flags') ?
  619.                     'flags' : 'enum';
  620.             $ret .= "=head2 $type $_\n\n";
  621.             $ret .= join ("\n", @{$info{$_}{pod}}) . "\n\n"
  622.                 if ($info{$_}{pod});
  623.             $ret .= podify_values ($_) . "\n";
  624.         }
  625.     }
  626.     
  627.     return $ret;
  628. }
  629.  
  630.  
  631. =item $string = podify_pods ($pods, $position)
  632.  
  633. Helper function to allow specific placement of generic pod within the auto
  634. generated pages. Pod sections starting out with =for position XXX, where XXX
  635. is one of the following will be placed at a specified position. In the case of
  636. pod that is to be placed after a particular section that doesn't exist, that
  637. pod will be still be placed there.
  638.  
  639. This function is called at all of the specified points through out the process
  640. of generating pod for a page. Any pod matching the I<position> passed will be
  641. returned, undef if no matches were found.  If I<position> is undef all pods
  642. without sepcific postion information will be returned. I<pods> is a reference
  643. to an array of pod hashes.
  644.  
  645. =over
  646.  
  647. =item * SYNOPSIS
  648.  
  649. After the NAME section
  650.  
  651. =item * DESCRIPTION
  652.  
  653. After the SYNOPSIS section.
  654.  
  655. =item * post_hierarchy
  656.  
  657. After the HIERARCHY section.
  658.  
  659. =item * post_interfaces
  660.  
  661. After the INTERFACE section.
  662.  
  663. =item * post_methods
  664.  
  665. After the METHODS section.
  666.  
  667. =item * post_properties
  668.  
  669. After the PROPERTIES section.
  670.  
  671. =item * post_signals
  672.  
  673. After the SIGNALS section.
  674.  
  675. =item * post_enums
  676.  
  677. After the ENUMS AND FLAGS section.
  678.  
  679. =item * SEE_ALSO
  680.  
  681. Replacing the autogenerated SEE ALSO section completely.
  682.  
  683. =item * COPYRIGHT
  684.  
  685. Replacing the autogenerated COPYRIGHT section completely.
  686.  
  687. =back
  688.  
  689. =cut
  690. sub podify_pods
  691. {
  692.     my $pods = shift;
  693.     my $position = shift;
  694.  
  695.     my $ret = '';
  696.  
  697.     if ($position)
  698.     {
  699.         foreach (@$pods)
  700.         {
  701.             $ret .= join ("\n", @{$_->{lines}})."\n\n"
  702.                 if (exists ($_->{position}) and 
  703.                     $_->{position} eq $position);
  704.         }
  705.     }
  706.     else
  707.     {
  708.         foreach (@$pods)
  709.         {
  710.             $ret .= join ("\n", @{$_->{lines}})."\n\n"
  711.                 unless ($_->{position});
  712.         }
  713.     }
  714.     return $ret ne '' ? $ret : undef;
  715. }
  716.  
  717. =item $string = podify_ancestors ($packagename)
  718.  
  719. Pretty-prints the ancestry of I<$packagename> from the Glib type system's
  720. point of view.  This uses Glib::Type->list_ancestors; see that function's
  721. docs for an explanation of why that's different from looking at @ISA.
  722.  
  723. Returns the new text as a string, or undef if I<$packagename> is not a
  724. registered GType.
  725.  
  726. =cut
  727. sub podify_ancestors {
  728.     my @anc;
  729.     eval { @anc = Glib::Type->list_ancestors (shift); 1; };
  730.     return undef unless (@anc or not $@);
  731.  
  732.     my $parents = [ reverse @anc ];
  733.  
  734.     my $depth = 0;
  735.     my $str = '  '.pop(@anc)."\n";
  736.     foreach (reverse @anc) {
  737.         $str .= "  " . "     "x$depth . "+----$_\n";
  738.         $depth++;
  739.     }
  740.     $str .= "\n";
  741.  
  742.     return ($str, $parents);
  743. }
  744.  
  745. =item $string = podify_interfaces ($packagename)
  746.  
  747. Pretty-print the list of GInterfaces that I<$packagename> implements.
  748. Returns the text as a string, or undef if the type implements no interfaces.
  749.  
  750. =cut
  751. sub podify_interfaces {
  752.     my @int;
  753.     eval { @int = Glib::Type->list_interfaces (shift); 1; };
  754.     return undef unless (@int or not defined ($@));
  755.     return '  '.join ("\n  ", @int)."\n\n";
  756. }
  757.  
  758. =item $string = podify_methods ($packagename)
  759.  
  760. Call C<xsub_to_pod> on all the xsubs under the key I<$packagename> in the
  761. data extracted by xsdocparse.pl.
  762.  
  763. Returns the new text as a string, or undef if there are no xsubs in
  764. I<$packagename>.
  765.  
  766. =cut
  767. sub podify_methods
  768. {
  769.     my $package = shift;
  770.     return undef unless $data->{$package};
  771.     my $xsubs = $data->{$package}{xsubs};
  772.     return undef unless $xsubs && @$xsubs;
  773.     # we will be re-using $package from here on out.
  774.  
  775.     my $str = '';
  776.     my $nfound = 0;
  777.     my $nused  = 0;
  778.     my $method;
  779.  
  780.     # based on rm's initial thought and then code/ideas by Marc 'HE'
  781.     # Brockschmidt, and Peter Haworth
  782.     @$xsubs = sort { 
  783.         my ($at, $bt);
  784.         for ($at=$a->{symname}, $bt=$b->{symname})
  785.         {
  786.             # remove prefixes
  787.             s/^.+:://;
  788.             # new's goto the front
  789.             s/^new/\x00/;
  790.             # group set's/get'ss
  791.             s/^(get|set)_(.+)/$2_$1/;
  792.             # put \<set\>'s with \<get\>'s
  793.             s/^(get|set)$/get_$1/;
  794.         }
  795.         # now actually do the sorting compare
  796.         $at cmp $bt; 
  797.     } @$xsubs;
  798.  
  799.     #$str .= "=over\n\n";
  800.     foreach (@$xsubs) {
  801.         # skip if the method is hidden
  802.         next if ($_->{hidden});
  803.         
  804.         $_->{symname} =~ m/^(?:([\w:]+)::)?([\w]+)$/;
  805.         $package = $1 || $_->{package};
  806.         $method = $2;
  807.  
  808.         # skip DESTROY altogether
  809.         next if $method eq 'DESTROY';
  810.  
  811.         ++$nfound;
  812.  
  813.         # don't document it if we can't actually call it.
  814.         if ($package->can ($method)) {
  815.             $str .= xsub_to_pod ($_, '=head2');
  816.             ++$nused;
  817.         } else {
  818.             # this print should only be temporary
  819.             print STDERR "missing: $package->$method\n";
  820.         }
  821.     }
  822.     #$str .= "=back\n\n";
  823.  
  824.     if ($nused == 0) {
  825.         # no xsubs were used.
  826.         if ($nfound > 0) {
  827.             # but some were found and not used.  
  828.             # say something to that effect.
  829.             print STDERR "No methods found for $package\n";
  830.             $str = "
  831.  
  832. Some methods defined for $package are not available in the particular
  833. library versions against which this module was compiled. 
  834.  
  835. ";
  836.         } else {
  837.             # no methods found, nothing to say
  838.             $str = undef;
  839.         }
  840.     }
  841.             
  842.     $str;
  843. }
  844.  
  845. =item $string = podify_see_alsos (@entries)
  846.  
  847. Creates a list of links to be placed in the SEE ALSO section of the page.
  848. Returns undef if nothing is in the input list.
  849.  
  850. =cut
  851.  
  852. sub podify_see_alsos
  853. {
  854.     my @entries = @_;
  855.  
  856.     return undef unless scalar @entries;
  857.     
  858.     # create the see also list
  859.     join (', ',
  860.         map {
  861.             if (/^\s*L</) {
  862.                 $_;
  863.             } else {
  864.                 "L<$_>";
  865.             }
  866.         }
  867.         @entries)
  868.         . "\n";
  869. }
  870.  
  871. =item $string = get_copyright
  872.  
  873. Returns a string that will/should be placed on each page.  You can control
  874. the text of this string by setting the package variable $COPYRIGHT to
  875. whatever you like.
  876.  
  877. If $COPYRIGHT is not set, we will attempt to create one for you, using the
  878. values of the variables $YEAR, $AUTHOR, and $MAIN_MOD.  $YEAR defaults to
  879. the current year, $AUTHORS defaults to 'The Gtk2-Perl Team', and $MAIN_MOD
  880. defaults to empty.  You want $MAIN_MOD to be set to the main module of your
  881. extension for the SEE ALSO section, and on the assumption that a decent
  882. license notice can be found in that module's doc, we point the reader there.
  883.  
  884. So, in general, you will want to specify at least one of these, so that you
  885. don't credit your work to us under the LGPL.
  886.  
  887. To set $COPYRIGHT, $AUTHORS, and/or $MAIN_MOD do something similar to the
  888. following in the first part of your postamble section in Makefile.PL.  All of
  889. the weird escaping is required because this is going through several levels of
  890. variable expansion.  All occurences of <br> in $COPYRIGHT are replaced with
  891. newlines, to make it easier to put in a multi-line string.
  892.  
  893.   POD_SET=\\\$\$Glib::GenPod::COPYRIGHT='Copyright 1999 team-foobar<br>LGPL';
  894.  
  895. Glib::MakeHelper::postamble_docs_full() does this sort of thing for you.
  896.  
  897. =cut
  898.  
  899. sub get_copyright
  900. {
  901.     my $str = $COPYRIGHT;
  902.     if (! $str) {
  903.         # construct a default.
  904.         $str = "\nCopyright (C) $YEAR $AUTHORS\n\n";
  905.         $str .= "This software is licensed under the LGPL;"
  906.              . " see $MAIN_MOD for a full notice.\n"
  907.             if $MAIN_MOD;
  908.     }
  909.  
  910.     # a way to make returns    
  911.     $str =~ s/<br>/\n/g;
  912.     return $str."\n";
  913. }
  914.  
  915. sub preprocess_pod
  916. {
  917.     my $pod = shift;
  918.  
  919.     foreach (@{$pod->{lines}})
  920.     {
  921.         # =for include filename
  922.         # =for include !cmd
  923.         if (/^=for\s+include\s+(!)?(.*)$/)
  924.         {
  925.             if ($1)
  926.             {
  927.                 chomp($_ = `$2`);
  928.             }
  929.             else
  930.             {
  931.                 if (open INC, "<$2")
  932.                 {
  933.                     local $/ = undef;
  934.                     $_ = <INC>;
  935.                 }
  936.                 else
  937.                 {
  938.                     carp "\n\nunable to open $2 for inclusion, at ".
  939.                          $pod->{filename}.':'.$pod->{line};
  940.                 }
  941.             }
  942.         }
  943.     }
  944. }
  945.  
  946. =back
  947.  
  948. =head2 Helpers
  949.  
  950. =over
  951.  
  952. =item $perl_type = convert_type ($ctypestring)
  953.  
  954. Convert a C type name to a Perl type name.
  955.  
  956. Uses %Glib::GenPod::basic_types to look for some known basic types,
  957. and uses Glib::Type->package_from_cname to look up the registered
  958. package corresponding to a C type name.  If no suitable mapping can
  959. be found, this just returns the input string.
  960.  
  961. =cut
  962. sub convert_type {
  963.     my $typestr = shift;
  964.  
  965.     $typestr =~ /^\s*                # leading space
  966.                   (?:const\s+)?            # maybe a const
  967.                   ([:\w]+)                # the name
  968.                   (\s*\*)?                # maybe a star
  969.                   \s*$/x;                # trailing space
  970.     my $ctype   = $1 || '!!';
  971.  
  972.     # variant type
  973.     $ctype =~ s/(?:_(ornull|own|copy|own_ornull|noinc))$//;
  974.     my $variant = $1 || "";
  975.  
  976.     my $perl_type;
  977.  
  978.     if (exists $basic_types{$ctype}) {
  979.         $perl_type = $basic_types{$ctype};
  980.  
  981.     } elsif ($ctype =~ m/::/) {
  982.         # :: is not valid in GLib type names, so there's no point
  983.         # in asking the GLib type system if it knows this name,
  984.         # because it's probably already a perl type name.
  985.         $perl_type = $ctype;
  986.  
  987.     } else {
  988.         eval
  989.         {
  990.             $perl_type = Glib::Type->package_from_cname ($ctype);
  991.             1;
  992.         } or do {
  993.             # this warning will have something to do with the
  994.             # package not being registered, a fact which will
  995.             # of interest to a person documenting or developing
  996.             # the documented module, but not to us developing
  997.             # the documentation generator.  thus, this warning
  998.             # doesn't need a line number attribution.
  999.             # let's strip that...
  1000.             $@ =~ s/\s*at (.*) line \d+\.$/./;
  1001.             warn "$@";
  1002.             # ... and fall back gracefully.
  1003.             $perl_type = $ctype;
  1004.         }
  1005.     }
  1006.  
  1007.     if ($variant && $variant =~ m/ornull/) {
  1008.         $perl_type .= " or undef";
  1009.     }
  1010.  
  1011.     $perl_type
  1012. }
  1013.  
  1014.  
  1015. =item $string = xsub_to_pod ($xsub, $sigprefix='')
  1016.  
  1017. Convert an xsub hash into a string of pod describing it.  Includes the
  1018. call signature, argument listing, and description, honoring special
  1019. switches in the description pod (arg and signature overrides).
  1020.  
  1021. =cut
  1022. sub xsub_to_pod {
  1023.     my $xsub = shift;
  1024.     my $sigprefix = shift || '';
  1025.     my $alias = $xsub->{symname};
  1026.     my $str;
  1027.  
  1028.     # ensure that if there's pod for this xsub, we have it now.
  1029.     # this should probably happen somewhere outside of this function,
  1030.     # but, eh...
  1031.     my @podlines = ();
  1032.     if (defined $xsub->{pod}) {
  1033.         @podlines = @{ $xsub->{pod}{lines} };
  1034.     }
  1035.  
  1036.     # look for annotations in the pod lines.
  1037.     # stuff in the pods overrides whatever we'd generate.
  1038.     my @signatures = ();
  1039.     if (@podlines) {
  1040.         # since we're modifying the list while traversing
  1041.         # it, go back to front.
  1042.         for (my $i = $#podlines ; $i >= 0 ; $i--) {
  1043.             if ($podlines[$i] =~ s/^=(for\s+)?signature\s+//) {
  1044.                 unshift @signatures, $podlines[$i];
  1045.                 splice @podlines, $i, 1;
  1046.             } elsif ($podlines[$i] =~ /^=(?:for\s+)?arg\s+
  1047.                                        (\$?[\w.]+)   # arg name
  1048.                                        (?:\s*\(([^)]*)\))? # type
  1049.                                        \s*
  1050.                                        (.*)$/x) { # desc
  1051.                 # this is a little convoluted, because we
  1052.                 # need to ensure that the args array and
  1053.                 # hash exist before using them.  we may be
  1054.                 # getting an =arg command on something that
  1055.                 # doesn't list this name in the xsub
  1056.                 # declaration.
  1057.                 $xsub->{args} = [] if not exists $xsub->{args};
  1058.                 my ($a, undef) =
  1059.                     grep { $_->{name} eq $1 }
  1060.                                   @{ $xsub->{args} };
  1061.                 $a = {}, push @{$xsub->{args}}, $a
  1062.                     if not defined $a;
  1063.                 $a->{name} = $1 if not defined $a->{name};
  1064.                 $a->{desc} = $3;
  1065.                 if ($2) {
  1066.                     if ($2 =~ m/^_*hide_*$/i) {
  1067.                         $a->{hide}++;
  1068.                     } else {
  1069.                         $a->{type} = $2;
  1070.                     }
  1071.                 }
  1072.                 # "just eat it!  eat it!  get yourself and
  1073.                 # egg and beat it!"  -- weird al
  1074.                 splice @podlines, $i, 1;
  1075.             }
  1076.         }
  1077.     }
  1078.  
  1079.     #
  1080.     # the call signature(s).
  1081.     #
  1082.     push @signatures, compile_signature ($xsub)
  1083.         unless @signatures;
  1084.  
  1085.     foreach (@signatures) {
  1086.         s/>(\w+)/>B<$1>/;
  1087.         $str .= "$sigprefix $_\n\n";
  1088.     }
  1089.  
  1090.     $str .= "=over\n\n";
  1091.  
  1092.     #
  1093.     # list all the arg types.
  1094.     #
  1095.     my @args;
  1096.     @args = @{ $xsub->{args} } if ($xsub->{args});
  1097.     shift @args unless $xsub->{function};
  1098.  
  1099.     $str .= "=over\n\n" if @args;
  1100.     foreach my $a (@args) {
  1101.         my $type;
  1102.         next if $a->{hide};
  1103.         if ($a->{name} eq '...') {
  1104.             $type = 'list';
  1105.         } else {
  1106.             if (not defined $a->{type}) {
  1107.                 warn "$alias: no type defined for arg"
  1108.                    . " \$$a->{name}\n";
  1109.                 $type = "(unknown)";
  1110.             } else {
  1111.                 $type = convert_arg_type ($a->{type});
  1112.             }
  1113.         }
  1114.         $str .= "=item * "
  1115.               . fixup_arg_name ($a->{name})
  1116.               . " ($type) "
  1117.               . ($a->{desc} ? $a->{desc} : "")
  1118.               . "\n\n";
  1119.     }
  1120.     $str .= "=back\n\n" if @args;
  1121.  
  1122.     if (@podlines) {
  1123.         shift @podlines;
  1124.         pop @podlines;
  1125.         $str .= join("\n", @podlines)."\n\n";
  1126.     }
  1127.  
  1128.     $str .= "May croak with a L<Glib::Error> in \$@ on failure.\n\n"
  1129.         if ($xsub->{gerror});
  1130.  
  1131.     $str .= "=back\n\n";
  1132.  
  1133.     $str
  1134. }
  1135.  
  1136. =item $string = compile_signature ($xsub)
  1137.  
  1138. Given an xsub hash, return a string with the call signature for that
  1139. xsub.
  1140.  
  1141. =cut
  1142. sub compile_signature {
  1143.     my $xsub = shift;
  1144.  
  1145.     my @args;
  1146.     @args = @{ $xsub->{args} } if ($xsub->{args});
  1147.  
  1148.     my $call;
  1149.  
  1150.     if ($xsub->{function}) {
  1151.         $call = $xsub->{symname};
  1152.     } else {
  1153.         # find the method's short name
  1154.         my $method = $xsub->{symname};
  1155.         $method =~ s/^(.*):://;
  1156.  
  1157.         my $package = $1 || $xsub->{package};
  1158.  
  1159.         # methods always eat the first arg as the instance.
  1160.         my $instance = shift @args;
  1161.  
  1162.         my $obj = defined ($instance->{type})
  1163.                 ? '$'.$instance->{name}
  1164.             : $package;
  1165.  
  1166.         $call = "$obj\-E<gt>$method";
  1167.     }
  1168.  
  1169.     # compile the arg list string
  1170.     my $argstr = join ", ", map {
  1171.             fixup_arg_name ($_->{name})
  1172.             . (defined $_->{default}
  1173.                ? '='.fixup_default ($_->{default})
  1174.                : '')
  1175.         } @args;
  1176.  
  1177.     # compile the return list string
  1178.     my @outlist = map { $_->{name} } @{ $xsub->{outlist} };
  1179.     if (defined $xsub->{return_type}) {
  1180.         my @retnames = map { convert_return_type_to_name ($_) }
  1181.                 @{ $xsub->{return_type} };
  1182.         unshift @outlist, @retnames;
  1183.     }
  1184.     my $retstr = @outlist
  1185.                ? (@outlist > 1
  1186.               ? "(".join (", ", @outlist).")"
  1187.               : $outlist[0]
  1188.              )." = "
  1189.            : (defined $xsub->{codetype} and
  1190.               $xsub->{codetype} eq 'PPCODE'
  1191.               ? 'list = '
  1192.               : ''
  1193.              );
  1194.     
  1195.     "$retstr$call ".($argstr ? "($argstr)" : "");
  1196. }
  1197.  
  1198. =item $string = fixup_arg_name ($name)
  1199.  
  1200. Prepend a $ to anything that's not the literal ellipsis string '...'.
  1201.  
  1202. =cut
  1203. sub fixup_arg_name {
  1204.     my $name = shift;
  1205.     my $sigil = $name eq '...' ? '' : '$';
  1206.     return $sigil.$name;
  1207. }
  1208.  
  1209. =item fixup_default
  1210.  
  1211. Mangle default parameter values from C to Perl values.  Mostly, this
  1212. does NULL => undef.
  1213.  
  1214. =cut
  1215. sub fixup_default {
  1216.     my $value = shift;
  1217.     return (defined ($value) 
  1218.             ? ($value eq 'NULL' ? 'undef' : $value)
  1219.         : '');
  1220. }
  1221.  
  1222. =item convert_arg_type
  1223.  
  1224. C type to Perl type conversion for argument types.
  1225.  
  1226. =cut
  1227. sub convert_arg_type { convert_type (@_) }
  1228.  
  1229.  
  1230. =item convert_return_type_to_name
  1231.  
  1232. C type to Perl type conversion suitable for return types.
  1233.  
  1234. =cut
  1235. sub convert_return_type_to_name {
  1236.     my $type = convert_type (@_);
  1237.     if ($type =~ s/^.*:://) {
  1238.         $type = lc $type;
  1239.     }
  1240.     return $type;
  1241. }
  1242.  
  1243. sub mkdir_p {
  1244.     my $path = shift;
  1245.     my @dirs = File::Spec->splitdir ($path);
  1246.     my $p = shift @dirs;
  1247.     do {
  1248.         mkdir $p or die "can't create dir $p: $!\n" unless -d $p;
  1249.         $p = File::Spec->catdir ($p, shift @dirs);
  1250.     } while (@dirs);
  1251. }
  1252.  
  1253. 1;
  1254. __END__
  1255.  
  1256. =back
  1257.  
  1258. =head1 SEE ALSO
  1259.  
  1260. L<Glib::ParseXSDoc>
  1261.  
  1262. =head1 AUTHORS
  1263.  
  1264. muppet bashed out the xsub signature generation in a few hours on a wednesday
  1265. night when band practice was cancelled at the last minute; he and ross
  1266. mcfarland hacked this module together via irc and email over the next few days.
  1267.  
  1268. =head1 COPYRIGHT AND LICENSE
  1269.  
  1270. Copyright (C) 2003-2004 by the gtk2-perl team
  1271.  
  1272. This library is free software; you can redistribute it and/or modify
  1273. it under the terms of the Lesser General Public License (LGPL).  For 
  1274. more information, see http://www.fsf.org/licenses/lgpl.txt
  1275.  
  1276. =cut
  1277.